// -*- Mode: C++; c-basic-offset: 8; indent-tabs-mode: nil -*-
//-
// Copyright (c) 2010 Michael Smith. All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
// 
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.

/// @file       ArduStationM.pde
/// @brief      Toplevel module for the ArduStationM firmware.

#include <stddef.h>
#include <inttypes.h>
#include <avr/pgmspace.h>
#include <LiquidCrystal.h>
#include <EEPROM.h>
#include "beep.h"
#include "buttons.h"
#include "decoder.h"
#include "hardware.h"
#include "markup.h"
#include "nvram.h"
#include "page.h"
#include "utils.h"
#include "watchdog.h"
#include "RotaryEncoder.h"

// complex pages
#include "alert.h"

#define LCD_COLUMNS    20                       ///< standard display for ArduStation
#define LCD_ROWS        4                       ///< standard display for ArduStation
LiquidCrystal   lcd(2, 3, 4, 5, 6, 7, 8);       ///< display driver instance

/// @name       Custom LCD characters
//@{
#define LCD_CHAR_LINK           0
#define LCD_CHAR_ROLL_LEFT      1
#define LCD_CHAR_ROLL_RIGHT     2
#define LCD_CHAR_UP_ARROW       3
#define LCD_CHAR_DOWN_ARROW     4
#define LCD_CHAR_MINUS_ONE      5
#define LCD_CHAR_BATTERY        6

const uint8_t   lcdCharRollLeft[]  = {0x00, 0x0e, 0x11, 0x11, 0x14, 0x0c, 0x1c, 0x00};
const uint8_t   lcdCharRollRight[] = {0x00, 0x0e, 0x11, 0x11, 0x05, 0x06, 0x07, 0x00};
const uint8_t   lcdCharUpArrow[]   = {0x04, 0x0e, 0x15, 0x04, 0x04, 0x04, 0x00, 0x00};
const uint8_t   lcdCharDownArrow[] = {0x00, 0x04, 0x04, 0x04, 0x15, 0x0e, 0x04, 0x00};
const uint8_t   lcdCharMinusOne[]  = {0x06, 0x1a, 0x02, 0x07, 0x00, 0x00, 0x00, 0x00};
const uint8_t   lcdCharBattery[]   = {0x0e, 0x1f, 0x11, 0x17, 0x1d, 0x11, 0x1f, 0x00};
//@}

Buttons         keypad;                         ///< keypad driver
RotaryEncoder   rotary(15, 16, 17);             ///< rotary encoder on A1/A2 gnd on A3
Watchdog        watchdog;                       ///< message receipt watchdog
NVRAM           nvram;                          ///< NVRAM driver
Markup          markup;                         ///< page markup engine
Beep            beep(TONE_PIN);                 ///< tune machine

PagePicker      pickerPage;                     ///< picker widget
PageSetup       setupPage;                      ///< setup page
PageAlert       alertPage;                      ///< alert message viewer

/// the about/copyright message
PROGMEM const prog_char aboutMessage[] =        // XXX why can't I use PSTR() here?
       "  ArduPilot Mega\n"
       "  groundstation\n"
       "    (c)2010\n"
       "    Michael Smith";
/// banner displayed at startup
PageText        welcomePage(aboutMessage, PAGE_BANNER_TIMEOUT);

/// Format string for the summary page - see the markup module for
/// a discussion of these codes.
PROGMEM const prog_char summaryPageFormat[] =
        "\x81    \x6\x83V\n"
        " \x84 \x85 \x86\n"
        " \x89m  \x8ams\x5  \x8b\x80\xdf\n"
        "\x87 \x88\n"
        "";
PageStatus      summaryPage(summaryPageFormat); ///< a page with some data

/// Message handlers
///
/// Use MSG_ANY to cause a handler to be called for every packet.
/// Use MSG_HEARTBEAT to cause a handler to be called on a regular basis
/// while we have a link to the controller.
/// StatusPage::notify should be called against every page that has
/// contents interested in the packet for the most rapid update rate.
///
struct message_handler msgHandlers[] = {
        // the watchdog should see every packet
        {MSG_ANY,       Watchdog::reset,        &watchdog},

        // Markup wants to see any packet that it may need later to
        // mark up a page.
        {MSG_HEARTBEAT, Markup::message,        &markup},
        {MSG_ATTITUDE,  Markup::message,        &markup},
        {MSG_LOCATION,  Markup::message,        &markup},
        {MSG_PRESSURE,  Markup::message,        &markup},

        // Messages that cause the summary page to update.
        {MSG_HEARTBEAT, PageStatus::notify,     &summaryPage},
        {MSG_ATTITUDE,  PageStatus::notify,     &summaryPage},
        {MSG_LOCATION,  PageStatus::notify,     &summaryPage},
        {MSG_NULL,      NULL}
};
Decoder         comm(msgHandlers);              ///< packet processor instance

